﻿using System;
using System.Security.Permissions;
using System.Windows.Forms;
using EnvDTE;
using uboot.ExtendedImmediateWindow.Implementation;

namespace uboot.ExtendedImmediateWindow
{
    /// <summary>
    /// Summary description for MyControl.
    /// </summary>
    public partial class ToolWindowControl : UserControl
    {
        public ToolWindowControl()
        {
            this.Visible = false;
            InitializeComponent();
            DoubleBuffered = true;
            intellisenseTextBox1.Text =
                "string msg = " + Environment.NewLine +
                "\tstring.Format(" + Environment.NewLine +
                "\t\"Hello World from inside {0}!\", " + Environment.NewLine +
                "\tthis);" + Environment.NewLine +
                "System.Console.WriteLine(msg);" + Environment.NewLine +
                Environment.NewLine +
                "/* You can see the result of this intruding method if you turn on the visual studio output window. (menue: View -> Output) */";
            this.Visible = true;
        }

        /// <summary>
        /// Let this control process the mnemonics.
        /// </summary>
        [UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
        protected override bool ProcessDialogChar(char charCode)
        {
            // If we're the top-level form or control, we need to do the mnemonic handling
            if (charCode != ' ' && ProcessMnemonic(charCode))
            {
                return true;
            }
            return base.ProcessDialogChar(charCode);
        }

        /// <summary>
        /// Enable the IME status handling for this control.
        /// </summary>
        protected override bool CanEnableIme
        {
            get
            {
                return true;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
        private void button1_Click(object sender, System.EventArgs e)
        {
            MessageBox.Show(this,
                            string.Format(System.Globalization.CultureInfo.CurrentUICulture, "We are inside {0}.button1_Click()", this.ToString()),
                            "Extended Immediate Tool Window");
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            new SplashScreen().Show();
        }

        private void resultControl1_ParentChanged(object sender, EventArgs e)
        {
            splitContainer1.Panel2Collapsed = (resultControl1.Parent != splitContainer1.Panel2);
        }

        internal class RunIntrudingMethodEventArgs : EventArgs
        {
            public string Source { get; set; }
        }

        internal event EventHandler<RunIntrudingMethodEventArgs> RunIntrudingMethod;

        internal class QueryContextTypeEventArgs : EventArgs
        {
            public Type ContextType { get; set; }
        }

        internal event EventHandler<QueryContextTypeEventArgs> QueryContextType;

        private void btRun_Click(object sender, EventArgs e)
        {
            if (RunIntrudingMethod != null)
                RunIntrudingMethod.Invoke(this, new RunIntrudingMethodEventArgs() { Source = intellisenseTextBox1.Text });
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (QueryContextType != null)
            {
                var args = new QueryContextTypeEventArgs();
                QueryContextType.Invoke(this, args);
                if (args.ContextType != null)
                    intellisenseTextBox1.ContextType = args.ContextType;
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="contextType"></param>
        public void SetContextType(Type contextType)
        {
            intellisenseTextBox1.ContextType = contextType;
            IsDebuggerConnected = true;
            btRun.Enabled = true;
            btRun.Text = "Run Intruding Method";
        }

        public bool IsDebuggerConnected { get; set; }

        private void connectToolStripButton_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            if (Connect != null) Connect.Invoke(this, EventArgs.Empty);
            this.Cursor = Cursors.Arrow;
        }

        private void intellisenseTextBox1_Load(object sender, EventArgs e)
        {
        }

        private void intellisenseTextBox1_SourceCodeChanged(object sender, EventArgs e)
        {
            if (!IsDebuggerConnected && !IsNotCottectedMessageShown)
            {
                string msg = "You are not yet connected to a debugger, intellisense environment may be wrong. Please connect before to a running debugger before executing the intruding method.";
                toolTip1.Show(msg, intellisenseTextBox1, 20000);
                IsNotCottectedMessageShown = true;
            }
        }

        private bool IsNotCottectedMessageShown { get; set; }

        private void resultControl1_Load(object sender, EventArgs e)
        {
        }

        internal void TellExecutionFailed(string message)
        {
            resultControl1.Enabled = false;
            resultControl1.TellSingleMessage(message);
        }

        internal void DisplayResultExpression(Expression expression)
        {
            resultControl1.Enabled = true;
            resultControl1.DisplayExpression(expression);
        }

        #region Aaron

        public bool Connect1()
        {
            this.RunIntrudingMethod += new EventHandler<ToolWindowControl.RunIntrudingMethodEventArgs>(View_RunIntrudingMethod);
            this.QueryContextType += new EventHandler<ToolWindowControl.QueryContextTypeEventArgs>(View_QueryContextType);
            this.Connect += new EventHandler(View_Connect);
            return true;
        }

        /// <summary>
        /// Do I neven need this
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void View_QueryContextType(object sender, ToolWindowControl.QueryContextTypeEventArgs e)
        {
            //if (QueryContextType != null)
            //    QueryContextType.Invoke(sender, e);
        }

        private void UpdateContextTypeIfChanged()
        {
            //if (IsConnected && DTE.Debugger.CurrentMode == dbgDebugMode.dbgBreakMode)
            //{
            //    string currentFunction = DTE.Debugger.CurrentStackFrame.FunctionName;

            //    Log("ExtendedImmediateAddInn - Connect");
            //    Log("Current Func: " + currentFunction);

            //    if (currentFunction != LastStackFunction)
            //    {
            //        Log("-> not cached already, have to analyze " + currentFunction);
            //        CurrentType = DTE.Debugger.GetCurrentType();
            //        Log("CurrentType: " + CurrentType.ToString());
            //        var context = GetContextType();
            //        Log("ContextType (compiled in background): " + context.ToString());
            //        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            //        ViewController.SetContextType(context);
            //        AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            //        LastStackFunction = currentFunction;
            //        Log("Done.");
            //    }
            //}
        }

        private void ViewController_QueryConnect(object sender, EventArgs e)
        {
            try
            {
                UpdateContextTypeIfChanged();
                IsDebuggerConnected = true;
            }
            catch (Exception exc)
            {
                MessageBox.Show("Konnte nicht verbinden: " + exc.Message + " " + exc.StackTrace);
            }
        }

        internal event EventHandler QueryConnect;

        /// <summary>
        /// Merge this with  View_Connect
        /// </summary>
        internal event EventHandler Connect;

        /// <summary>
        /// Merge this with  Connect
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void View_Connect(object sender, EventArgs e)
        {
            if (QueryConnect != null) QueryConnect.Invoke(this, EventArgs.Empty);
        }

        private void View_RunIntrudingMethod(object sender, ToolWindowControl.RunIntrudingMethodEventArgs e)
        {
            if (RunIntrudingMethod != null) RunIntrudingMethod.Invoke(sender, e);
        }

        private void ViewController_RunIntrudingMethod(object sender, ToolWindowControl.RunIntrudingMethodEventArgs e)
        {
            Execute(e.Source);
        }

        private void Execute(string source)
        {
            var refAssemblies = DTE.Debugger.GetResolver().ReferencedAssemblies;
            var localMembers = LocalReachableMembers.ToList();

            Injector injector = new Injector(DTE.Debugger, source, refAssemblies, localMembers);
            injector.Results += new EventHandler<Injector.ResultEventArgs>(injector_Results);
            injector.Execute();
        }

        #endregion Aaron
    }
}